package com.qianniu.napi.admin.web;

import akka.actor.ActorRef;
import akka.actor.Props;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.common.base.Strings;
import com.qianniu.napi.admin.entity.Jinfo;
import com.qianniu.napi.admin.entity.MerchantApp;
import com.qianniu.napi.admin.entity.wxbean.WxIntoVo;
import com.qianniu.napi.admin.service.*;
import com.qianniu.napi.admin.service.akka.AkkaServer;
import com.qianniu.napi.admin.service.akka.ResourceActor;
import com.qianniu.napi.common.config.Constants;
import com.qianniu.napi.common.util.*;
import com.riversoft.weixin.mp.base.AppSetting;
import com.riversoft.weixin.mp.template.Data;
import com.riversoft.weixin.mp.template.Templates;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.codec.binary.Hex;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.*;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * <p>
 * 商家分店应用信息
 * </p>
 *
 * @author chenxuebin
 * @since 2018-08-22
 */
@RestController
public class MerchantAppController {

    private static final Logger logger = LoggerFactory.getLogger(MerchantAppController.class);

    @Autowired
    private IMerchantAppService merchantappService;

    @RequestMapping("/api/merchantapp/list")
    @ResponseBody
    public Jinfo list(@RequestParam(value = "status", required = false) String status,
                      @RequestParam(value = "pageIndex", required = false) Integer pageIndex,
                      @RequestParam(value = "pageSize", required = false) Integer pageSize,
                      HttpServletRequest req) {
        Jinfo info = new Jinfo();
        if (pageSize == null) pageSize = 10;
        Page page = new Page(pageIndex, pageSize);
        page = merchantappService.selectPage(page, new EntityWrapper<MerchantApp>()
                .eq("uid", ObjectUtil.getUid())
                .eq("state", 1));
        info.setInfo(page.getRecords());
        return info;
    }

    @RequestMapping("/api/merchantapp/add")
    @ResponseBody
    public Jinfo merchantappAdd(@Valid MerchantApp bean,
                                BindingResult bindingResult, HttpServletRequest req) {
        Jinfo info = new Jinfo();
        // 字段校验
        if (bindingResult.hasErrors()) {
            logger.debug("There are errors! {}", bindingResult);
            info.setMsg("There are errors! " + bindingResult);
            info.setCode(400);
            return info;
        }
        bean.setCreatetime(new Date());
        bean.insert();
        //更新素材资源
        AkkaServer.system.actorOf(Props.create(ResourceActor.class))
                .tell("MerchantApp@"+bean.getId()+"@insert", ActorRef.noSender());
        return info;
    }

    @RequestMapping("/admin/bean/initmkey")
    @ResponseBody
    public Jinfo initmkey(@RequestParam("mpid") String mpid) {

        Jinfo info = new Jinfo();
        Long mid = ObjectUtil.getMid();
        MerchantApp ma = merchantappService.selectById(mpid);
//        生成规则 = mid+mpid+[uid]+random+appid+apptype
        String mkey = mid + "__" + mpid + "____" + ObjectUtil.randomStrings(8, 1).get(0) + "__" + ma.getAppid() + "__" + ma.getAppType();
        logger.debug(">>>>>>>>before encrypt mkey=", mkey);
        mkey = AesUtil.encrypt(mkey, Constants.ENCODE_KEY);
        logger.debug(">>>>>>>>after encrypt mkey=", mkey);
        info.setInfo(mkey);
        return info;
    }

    @RequestMapping("/api/merchantapp/modify")
    @ResponseBody
    public Jinfo merchantappUpdate(HttpServletRequest req,
                                   MerchantApp bean) {
        Jinfo info = new Jinfo();
        bean.setModifytime(new Date());
        bean.updateById();
        //更新素材资源
        AkkaServer.system.actorOf(Props.create(ResourceActor.class))
                .tell("MerchantApp@"+bean.getId()+"@update", ActorRef.noSender());
        return info;
    }

    @RequestMapping("/api/merchantapp/detail")
    @ResponseBody
    public Jinfo getMerchantAppDetailById(@RequestParam("token") String token,
                                          @RequestParam("id") long id, HttpServletRequest req
    ) {
        Jinfo info = new Jinfo();
        MerchantApp bean = merchantappService.selectById(id);
        info.setInfo(bean);
        return info;
    }

    @RequestMapping("/api/wxpay/applytest")
    @ResponseBody
    public Jinfo wxpayApplytest(@RequestParam("token") String token,
                                @RequestParam("id") long id,
                                HttpServletRequest req
    ) throws IOException{
        Jinfo info = new Jinfo();
        // 加载商户私钥（privateKey：私钥字符串）
        String privateKey = "o0yu65kfd0avmw7hey1fk6dvrd5e89k3";

        String mchSerialNo = "o0yu65kfd0avmw7hey1fk6dvrd5e89k3";

        String mchId = "1592907601";
        String apiV3Key = "o0yu65kfd0avmw7hey1fk6dvrd5e89k3";

        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));

        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3秘钥）
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));

        // 初始化httpClient
        HttpClient httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();

        return info;
    }

//    @ApiOperation(value = "微信图片上传", notes = "微信图片上传")
//    @PostMapping("/uploadWxImg")
//    public Result uploadWxImg(MultipartFile file) {
//        try {
//            String mch_id = "*******";//微信服务商商户号
//            String payKey = "****************";//服务商商户号对应的商户密钥
//            File file1 = new File(file.getOriginalFilename());
//            FileUtils.copyInputStreamToFile(file.getInputStream(), file1);
//            //D:\\666\\apiclient_cert.p12 证书存放位置
//            String str = UploadDemo.upload(file1, mch_id, "/data/soft/cert_wx/1592907601/apiclient_cert.p12",
//                    "https://api.mch.weixin.qq.com/secapi/mch/uploadmedia", payKey);
//            // 会在本地产生临时文件，用完后需要删除 如果发现代码不完整的qq1023732997
//            if (file1.exists()) {
//                file1.delete();
//            }
//
//            return Result.success(str);
//        } catch (Exception e) {
//            logger.error("系统出错:{}", e);
//            return Result.fail();
//        }
//    }

//    @ApiOperation(value = "小微商户微信进件", notes = "小微商户")
//    @PostMapping("/wx/into")
//    public Result addWxInto(@Valid @RequestBody WxIntoVo intoVo) {
//        try {
//            String contactName = intoVo.getContactName(); // 超级管理员姓名
//            String contactIdNum = intoVo.getContactIdNum(); // 身份证号码
//            String contactMobile = intoVo.getContactMobile(); // 手机号码
//            String contactMail = intoVo.getContactMail(); // 联系邮箱 作者qq1023732997不会的呼叫
//            String microName = intoVo.getMicroName(); // 门店名称（也用于简称）
//
//            // 门店省市编码
//            // 参考：https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/ecommerce/applyments/chapter4_1.shtml
//            String microAddressCode = intoVo.getMicroAddressCode();
//            String microAddress = intoVo.getMicroAddress(); // 门店地址
//
//            String idCardCopy = intoVo.getIdCardCopy(); // 身份证正面照
//            String idCardNational = intoVo.getIdCardNational(); // 身份证反面照
//
//            String cardPeriodBegin = intoVo.getCardPeriodBegin(); // 身份证有效期开始时间2018-10-23
//            String cardPeriodEnd = intoVo.getCardPeriodEnd();// 身份证有效期结束时间2011-06-24
//            String servicePhone = intoVo.getServicePhone();// 客服电话； 无特殊使用管理员手机号码
//            String accountBank = intoVo.getAccountBank(); // 开户银行
//            String bankAddressCode = intoVo.getBankAddressCode(); // 开户银行省市编码至少精确到市，详细参见《省市区编号对照表》 示例值：110000；
//
//            // 1、“开户银行”为17家直连银行无需填写 作者qq:1023732997 不懂的加我
//            // 2、“开户银行”为其他银行，则开户银行全称（含支行）和开户银行联行号二选一
//            // 3、需填写银行全称，如"深圳农村商业银行XXX支行"，详细参见《开户银行全称（含支行）对照表》
//            // 示例值：昆明市西山区西山支行
//            String bankName = intoVo.getBankName(); // 开户银行全称（含支行]
//            String accountNumber = intoVo.getAccountNumber(); // 银行账号
//            ApplymentBo t = new ApplymentBo();
//            String str = t.exe(contactName, contactIdNum, contactMobile, contactMail, microName, microAddressCode, microAddress, idCardCopy, idCardNational,
//                    cardPeriodBegin, cardPeriodEnd, servicePhone, accountBank, bankAddressCode, bankName, accountNumber);
//            return Result.success(str);
//        } catch (Exception e) {
//            log.error("系统出错:{}", e);
//            return Result.fail("系统出错");
//        }
//    }

    /**
     * 进件
     *
     * @param contactName      管理员姓名
     * @param contactIdNum     管理员身份证号码
     * @param contactMobile    管理员手机号码
     * @param contactMail      管理员邮箱
     * @param microName        门店名称
     * @param microAddressCode 门店编码，参考：https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/ecommerce/applyments/chapter4_1.shtml
     * @param microAddress     门店地址
     * @param idCardCopy       身份证正面照片
     * @param idCardNational   身份证反面照片
     * @param cardPeriodBegin  身份证有效期开始时间，格式：2011-06-24
     * @param cardPeriodEnd    身份证有效期结束时间，格式：2011-06-24
     * @param servicePhone     客户电话
     * @param accountBank      开户行银行名称
     * @param bankAddressCode  开户行编码
     * @param bankName         开户银行全称（含支行]
     * @param accountNumber    银行卡号
     * @throws Exception
     */
    public String exe(String contactName, String contactIdNum, String contactMobile,
                      String contactMail, String microName, String microAddressCode,
                      String microAddress, String idCardCopy, String idCardNational,
                      String cardPeriodBegin, String cardPeriodEnd, String servicePhone,
                      String accountBank, String bankAddressCode,
                      String bankName, String accountNumber) throws Exception {

        // 获取微信平台证书 并解析方法在后面
        String certString = CertUtil.getCertStr();
        ByteArrayInputStream stringStream = new ByteArrayInputStream(certString.getBytes());
        // 下面所有加密参数需要的对象
        X509Certificate certx = PemUtil.loadCertificate(stringStream);

        // 超级管理员信息
        Map<String, Object> contact_info = new HashMap<String, Object>();
        String contact_name = RsaEncryptUtil.rsaEncryptOAEP(contactName, certx); // 超级管理员姓名
        String contact_id_number = RsaEncryptUtil.rsaEncryptOAEP(contactIdNum, certx); // 超级管理员身份证件号码
        String mobile_phone = RsaEncryptUtil.rsaEncryptOAEP(contactMobile, certx);// 联系手机
        String contact_email = RsaEncryptUtil.rsaEncryptOAEP(contactMail, certx);// 联系邮箱
        contact_info.put("contact_name", contact_name);
        contact_info.put("contact_id_number", contact_id_number);
        contact_info.put("mobile_phone", mobile_phone);
        contact_info.put("contact_email", contact_email);

        // 主体资料
        String subject_type = "SUBJECT_TYPE_INDIVIDUAL"; // 主体类型
        String micro_biz_type = "MICRO_TYPE_STORE"; // 小微经营类型
        String micro_name = microName; // 门店名称
        String micro_address_code = microAddressCode; // 门店省市编码
        String micro_address = microAddress; // 门店街道名称

        String store_entrance_pic = ""; // 门店门口照片 图片上传接口获取
        String micro_indoor_copy = ""; // 店内环境照片 图片上传接口获取

        // 证件类型，IDENTIFICATION_TYPE_IDCARD
        String id_doc_type = "IDENTIFICATION_TYPE_IDCARD";

        String id_card_name = RsaEncryptUtil.rsaEncryptOAEP(contactName, certx); // 身份证姓名
        String id_card_number = RsaEncryptUtil.rsaEncryptOAEP(contactIdNum, certx); // 身份证号码
        // String card_period_begin = "2011-06-24"; // 身份证有效期开始时间示例值：2026-06-06
        // String card_period_end = "2021-06-24"; // 身份证有效期结束时间示例值：2026-06-06

        Map<String, Object> subject_info = new HashMap<String, Object>(); // 主体资料
        Map<String, Object> micro_biz_info = new HashMap<String, Object>(); // 小微商户辅助材料
        Map<String, Object> micro_store_info = new HashMap<String, Object>(); // 门店场所信息
        Map<String, Object> identity_info = new HashMap<String, Object>(); // 经营者身份证件
        Map<String, Object> id_card_info = new HashMap<String, Object>(); // 身份证信息

        micro_store_info.put("micro_name", micro_name);
        micro_store_info.put("micro_address_code", micro_address_code);
        micro_store_info.put("micro_address", micro_address);
        micro_store_info.put("store_entrance_pic", store_entrance_pic);
        micro_store_info.put("micro_indoor_copy", micro_indoor_copy);

        micro_biz_info.put("micro_biz_type", micro_biz_type);
        micro_biz_info.put("micro_store_info", micro_store_info);

        id_card_info.put("id_card_copy", idCardCopy);
        id_card_info.put("id_card_national", idCardNational);
        id_card_info.put("id_card_name", id_card_name);
        id_card_info.put("id_card_number", id_card_number);
        id_card_info.put("card_period_begin", cardPeriodBegin);
        id_card_info.put("card_period_end", cardPeriodEnd);

        identity_info.put("id_doc_type", id_doc_type);
        identity_info.put("id_card_info", id_card_info);

        subject_info.put("subject_type", subject_type);
        subject_info.put("micro_biz_info", micro_biz_info);
        subject_info.put("identity_info", identity_info);

        // 经营资料
        // String merchant_shortname = "张三停车场"; // 商户简称
        // String service_phone = "0755222222"; // 客服电话
        Map<String, Object> business_info = new HashMap<String, Object>();
        business_info.put("merchant_shortname", microName);
        business_info.put("service_phone", servicePhone);

        // 结算规则
        // 入驻结算规则ID;请选择结算规则ID，详细参见《费率结算规则对照表》 示例值：小微商户：703
        String settlement_id = "716";//
        String qualification_type = "电竞酒店"; // 所属行业;请填写所属行业名称，建议参见《费率结算规则对照表》 示例值：餐饮
        Map<String, Object> settlement_info = new HashMap<String, Object>();
        settlement_info.put("settlement_id", settlement_id);
        settlement_info.put("qualification_type", qualification_type);

        // 收款银行卡
        // 账户类型 若主体为小微，可填写：经营者个人银行卡 枚举值：
        // BANK_ACCOUNT_TYPE_PERSONAL：经营者个人银行卡
        // 示例值：BANK_ACCOUNT_TYPE_CORPORATE
        String bank_account_type = "BANK_ACCOUNT_TYPE_PERSONAL";

        String account_name = RsaEncryptUtil.rsaEncryptOAEP(contactName, certx); // 开户名称（该字段需进行加密处理）
        // String account_bank = "建设银行"; // 开户银行开户银行，详细参见《开户银行对照表》 示例值：工商银行
        // String bank_address_code = "440300"; // 开户银行省市编码至少精确到市，详细参见《省市区编号对照表》 示例值：110000

        // 1、“开户银行”为17家直连银行无需填写
        // 2、“开户银行”为其他银行，则开户银行全称（含支行）和开户银行联行号二选一
        // 3、需填写银行全称，如"深圳农村商业银行XXX支行"，详细参见《开户银行全称（含支行）对照表》
        // 示例值：施秉县农村信用合作联社城关信用社
        // String bank_name = ""; // 开户银行全称（含支行]
        String account_number = RsaEncryptUtil.rsaEncryptOAEP(accountNumber, certx); // 银行账号（该字段需进行加密处理）
        Map<String, Object> bank_account_info = new HashMap<String, Object>();
        bank_account_info.put("bank_account_type", bank_account_type);
        bank_account_info.put("account_name", account_name);
        bank_account_info.put("account_bank", accountBank);
        bank_account_info.put("bank_address_code", bankAddressCode);
        bank_account_info.put("bank_name", bankName);
        bank_account_info.put("account_number", account_number);

//        String business_code = OrderIdUtils.getGoodsOrderId(); // 申请单号
        String business_code = ""; // 申请单号
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("business_code", business_code);
        map.put("contact_info", contact_info);
        map.put("subject_info", subject_info);
        map.put("business_info", business_info);
        map.put("settlement_info", settlement_info);
        map.put("bank_account_info", bank_account_info);
        try {
            String body = JSONObject.toJSONString(map);
            String str = HttpUrlUtil.sendPost(body);
            System.out.println(str);
            return str;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @RequestMapping("/test/fensi/list")
    @ResponseBody
    public Jinfo fensiList(@RequestParam("type") int type
    ) {
        Jinfo info = new Jinfo();
        List<Fen> list = new ArrayList<Fen>();
        for (int n = 0; n < 5; n++) {
            Fen fen = new Fen();
            fen.setId(n + 1);
            fen.setName("刘三君");
            fen.setGuanzhu(true);
            fen.setTouxiang("http://img.qianniu010.com/vmall/132.jpg");
            if (n % 2 == 1) {
                fen.setTouxiang("http://img.qianniu010.com/vmall/133.jpg");
                fen.setGuanzhu(false);
            }
            list.add(fen);
        }

        info.setInfo(list);
        return info;
    }

    @RequestMapping("/test/wxtpl/send")
    @ResponseBody
    public Jinfo wxtplsend(@RequestParam("tplid") int type) {

        Jinfo info = new Jinfo();

        AppSetting setting = new AppSetting("wxebeaf0bd5f05654a","f7c576d5aa747af66e03d66dd0eb8ccc");
        Templates templates = Templates.with(setting);

        String openid = "o703E1Nmv4qIEGQd__p8HuzyqiUE";
        String tplid = "yvbVL2pcePNO_-I_YcEUX7_pFC4tJ5T1hPHwGj4YWCI";

        Map<String,Data> map = new HashMap<String,Data>();
        Data first = new Data();
        first.setValue("牛哥你好，你上周的业绩如下：");
        first.setColor("#FF0000");
        map.put("first",first);

        Data keyword1 = new Data();
        keyword1.setValue("001");
        keyword1.setColor("#173177");
        map.put("keyword1",keyword1);

        Data keyword2 = new Data();
        keyword2.setValue("2019-05-7至2019-05-15");
        keyword2.setColor("#173177");
        map.put("keyword2",keyword2);

        Data keyword3 = new Data();
        keyword3.setValue("项目提成：2500元、奖金1000元");
        keyword3.setColor("#173177");
        map.put("keyword3",keyword3);

        Data remark = new Data();
        remark.setValue("欢迎进入公司内网查看详细统计信息。");
        remark.setColor("#FF0000");
        map.put("remark",remark);

        templates.send(openid,tplid,"",map);

        return info;
    }

    public class Fen {

        private int id;
        private String name;
        private String touxiang;
        private boolean isGuanzhu;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getTouxiang() {
            return touxiang;
        }

        public void setTouxiang(String touxiang) {
            this.touxiang = touxiang;
        }

        public boolean isGuanzhu() {
            return isGuanzhu;
        }

        public void setGuanzhu(boolean guanzhu) {
            isGuanzhu = guanzhu;
        }
    }

    private void setup() throws IOException {
//        // 加载商户私钥（privateKey：私钥字符串）
//        PrivateKey merchantPrivateKey = PemUtil
//                .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
//
//        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3秘钥）
//        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
//                new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));
//
//        // 初始化httpClient
//        HttpClient httpClient = WechatPayHttpClientBuilder.create()
//                .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
//                .withValidator(new WechatPay2Validator(verifier)).build();
    }

    // ============ 微信上传方法 ==============
    /**
     * 真实上传方法
     *
     * @param file
     * @param mch_id
     * @param keyStoreUrl
     * @param requestUrl
     * @param payKey      <p>
     *                    对上次文件进行MD5获取其Hash
     * @param payKey      签名密钥
     * @return 待签名字符串
     */

    public static String upload(File file, String mch_id, String keyStoreUrl, String requestUrl, String payKey) {

        try {
            String media_hash = md5HashCode(new FileInputStream(file));
            String sign_type = "HMAC-SHA256";
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("mch_id", mch_id);
            paramMap.put("media_hash", media_hash);
            paramMap.put("sign_type", sign_type);
            String sign = sha256Sign(paramMap, payKey);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            multipartEntityBuilder.addTextBody("mch_id", mch_id, ContentType.MULTIPART_FORM_DATA);
            multipartEntityBuilder.addBinaryBody("media", file, ContentType.create("image/jpg"), file.getName());
            multipartEntityBuilder.addTextBody("media_hash", media_hash, ContentType.MULTIPART_FORM_DATA);
            multipartEntityBuilder.addTextBody("sign_type", sign_type, ContentType.MULTIPART_FORM_DATA);
            multipartEntityBuilder.addTextBody("sign", sign, ContentType.MULTIPART_FORM_DATA);

            FileInputStream instream = null;
            SSLContext sslcontext = null;
            try {
                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                instream = new FileInputStream(new File(keyStoreUrl));
                keyStore.load(instream, mch_id.toCharArray());// 这里写密码..默认是你的MCHID
                sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            } catch (Exception e) {
                logger.error("官方微信--证书加载失败!{}", e);
            } finally {
                try {
                    if (instream != null) {
                        instream.close();
                    }
                } catch (IOException e) {
                    logger.error("官方微信--证书加载失败!{}", e);
                }
            }

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            try {
                HttpPost httpPost = new HttpPost(requestUrl);
                RequestConfig config = RequestConfig.custom().setConnectTimeout(10000).setConnectionRequestTimeout(10000).setSocketTimeout(10000).build();
                httpPost.setConfig(config);
                //这里的Content-type要设置为"multipart/form-data"，否则返回“参数填写有误，请检查后重试”
                httpPost.addHeader(HTTP.CONTENT_TYPE, "multipart/form-data; charset=UTF-8");
                httpPost.addHeader(HTTP.USER_AGENT, "wxpay sdk java v1.0 " + mch_id);
                httpPost.setEntity(multipartEntityBuilder.build());
                CloseableHttpResponse response = httpclient.execute(httpPost);
                String result = EntityUtils.toString(response.getEntity(), "UTF-8");
                logger.info("官方微信--请求返回结果：{}", result);
                return result;
            } catch (Exception e) {
                logger.error("官方微信--请求失败！{}", e);
            }

        } catch (Exception e) {
            logger.error("系统出错:{}", e);
        }
        return null;
    }

    /**
     * 对上次文件进行MD5获取其Hash值
     *
     * @param fis
     * @return
     */

    public static String md5HashCode(InputStream fis) {
        try {
            MessageDigest MD5 = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[8192];
            int length;
            while ((length = fis.read(buffer)) != -1) {
                MD5.update(buffer, 0, length);
            }
            return new String(Hex.encodeHex(MD5.digest()));
        } catch (Exception e) {
            logger.error("系统出错:{}", e);
            return null;
        }
    }

    /**
     * 获取HMAC-SHA256签名
     *
     * @param paramMap 签名参数（sign不参与签名）
     * @param key      签名密钥
     * @param paramMap 签名参数（sign字段不参与签名）
     * @param
     * @param paramMap 签名参数（sign字段不参与签名）
     * @param paramMap 签名参数（sign字段不参与签名
     * @return 待签名字符串
     */
    public final static String sha256Sign(Map<String, Object> paramMap, String key) {
        try {
            String payParam = getSignTemp(paramMap, key);
            logger.info("签名原文:{}", payParam);
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] array = sha256_HMAC.doFinal(payParam.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            String sign = sb.toString().toUpperCase();
            logger.info("签名结果:{}", sign);
            return sign;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取签名参数字符串
     *
     * @param paramMap 签名参数（sign字段不参与签名）
     * @param payKey   签名密钥
     * @return 待签名字符串
     */

    private final static String getSignTemp(Map<String, Object> paramMap, String payKey) {
        ArrayList<String> keyList = new ArrayList<>(paramMap.keySet());
        Collections.sort(keyList);
        StringBuilder signParam = new StringBuilder();
        for (String key : keyList) {
            if ("sign".equals(key) && !Strings.isNullOrEmpty(paramMap.get(key).toString())) {
                signParam.append(key).append("=").append(paramMap.get(key)).append("&");
            }
        }
        System.out.println(signParam.length());
        signParam.delete(signParam.length() - 1, signParam.length());
        signParam.append("&key=").append(payKey);
        //注意这里返回的值 一定是把mch_id等拼接起来的一大串
        return signParam.toString();
    }

}
